<script setup lang="tsx">
import { reactive, ref, shallowRef, watch } from 'vue';
import type { FormInst, FormItemRule } from 'naive-ui';
import { NSelect } from 'naive-ui';
import { $t } from '@/locales';
import {
  fetchGetAllPositions,
  fetchGetAllRoles,
  fetchGetOrgUnitTree,
  fetchGetUserResponsibilities,
  fetchSaveUserResponsibilities
} from '@/service/api';
import { useAuthStore } from '@/store/modules/auth';
import { CollectionUtil, StringUtil } from '@/utils/z';

defineOptions({
  name: 'UserResponsibilitiesSetting'
});

interface Props {
  userId: string;
}

const props = defineProps<Props>();

interface Emits {
  (e: 'submitted'): void;
}

const emit = defineEmits<Emits>();

const visible = defineModel<boolean>('visible', {
  default: false
});

const authStore = useAuthStore();

const formRef = ref<FormInst | null>(null);

function closeModal() {
  visible.value = false;
}

type Model = Api.SystemManage.UserResponsibilities;

const model: Model = reactive(createDefaultModel());

function createDefaultModel(): Model {
  return {
    userId: props.userId,
    roleIds: [],
    orgPositions: []
  };
}

const rules = {
  roleIds: [
    {
      key: 'roleIds',
      required: true,
      validator(rule: FormItemRule, value: string[]) {
        if (rule.required && CollectionUtil.isEmpty(value)) {
          return new Error('角色不能为空');
        }
        if (authStore.userInfo.isAdmin && value.length > 1) {
          return new Error('只能设置一个角色');
        }
        return true;
      }
    }
  ],
  orgPositions: [
    {
      key: 'orgPositions',
      required: true,
      validator(rule: FormItemRule, value: Api.SystemManage.OrgIdPositionId[]) {
        if (rule.required && CollectionUtil.isEmpty(value)) {
          return new Error('组织岗位不能为空');
        }
        const bindIds: string[] = [];
        for (let i = value.length - 1; i >= 0; i -= 1) {
          if (StringUtil.isEmpty(value[i].orgId) || StringUtil.isEmpty(value[i].positionId)) {
            return new Error('组织岗位数据含有错误');
          }
          const bindId = value[i].orgId + value[i].positionId;
          if (bindIds.includes(bindId)) {
            return new Error('组织岗位数据含有错误');
          }
          bindIds.push(bindId);
        }
        return true;
      }
    }
  ]
};

const roleOptions = shallowRef<CommonType.Option[]>([]);

type OrgUnitTree = Api.SystemManage.OrgUnitTree;

const orgUnitTree = shallowRef<OrgUnitTree[]>([]);

type PositionRecord = Record<string, CommonType.Option[]>;

const positionRecord = ref<PositionRecord>({});

async function addPositionRecord(index: number, orgId: string) {
  model.orgPositions.splice(index, 1, { orgId, positionId: '' });
  if (orgId in positionRecord.value) return;
  const { error, data } = await fetchGetAllPositions(orgId);
  if (!error && data) {
    positionRecord.value[orgId] = data;
    positionRecord.value = { ...positionRecord.value };
  }
}

async function handleInitOptions() {
  if (authStore.userInfo.isAdmin) {
    fetchGetAllRoles().then(({ error, data }) => {
      if (!error && data) {
        roleOptions.value = data;
      }
    });
  } else {
    fetchGetAllRoles()
      .then(({ error, data }) => {
        if (!error && data) {
          roleOptions.value = data;
        }
        return fetchGetOrgUnitTree();
      })
      .then(({ error, data }) => {
        if (!error && data) {
          orgUnitTree.value = data;
        }
      });
  }
}

async function handleUseResponsibilities() {
  const { error, data } = await fetchGetUserResponsibilities(props.userId);
  if (!error && data) {
    Object.assign(model, data);
    if (model.orgPositions.length > 0) {
      for (let i = 0; i < model.orgPositions.length; i += 1) {
        const orgId = model.orgPositions[i].orgId;
        fetchGetAllPositions(orgId).then(res => {
          if (!res.error && res.data) {
            positionRecord.value[orgId] = res.data;
            positionRecord.value = { ...positionRecord.value };
          }
        });
      }
    }
  }
}

async function handleInitModel() {
  Object.assign(model, createDefaultModel());
  await handleInitOptions();
  await handleUseResponsibilities();
}

function addNewItem(index: number) {
  if (model.orgPositions.length === index + 1) {
    model.orgPositions.push({ orgId: '', positionId: '' });
  } else {
    model.orgPositions.splice(index + 1, 0, { orgId: '', positionId: '' });
  }
}

function removeItem(index: number) {
  if (model.orgPositions.length < 2) return;
  model.orgPositions.splice(index, 1);
}

async function handleSubmit() {
  if (authStore.userInfo.isAdmin) {
    await formRef.value?.validate(
      errors => {
        // eslint-disable-next-line no-console
        console.log(errors);
      },
      rule => {
        return ['roleIds'].includes(rule?.key || '');
      }
    );
  } else {
    await formRef.value?.validate();
  }
  const { error, data } = await fetchSaveUserResponsibilities(model);
  if (!error && data) {
    window.$message?.success($t('common.updateSuccess'));
    emit('submitted');
    closeModal();
  }
}

watch(visible, () => {
  if (visible.value) {
    handleInitModel();
  }
});
</script>

<template>
  <NModal
    v-model:show="visible"
    :title="$t('page.manage.user.responsibilities')"
    :closable="false"
    preset="card"
    :segmented="{ content: true }"
    class="w-800px"
  >
    <NForm ref="formRef" label-placement="left" :label-width="80" :model="model" :rules="rules">
      <NGrid :x-gap="8" :y-gap="8">
        <NFormItemGi span="24" :label="$t('page.manage.user.userRole')" path="roleIds">
          <NSelect
            v-model:value="model.roleIds"
            multiple
            filterable
            :options="roleOptions"
            :max-tag-count="3"
            :placeholder="$t('page.manage.user.form.userRole')"
          />
        </NFormItemGi>
        <template v-if="!authStore.userInfo.isAdmin">
          <NFormItemGi span="24" :label="$t('page.manage.user.orgPositionNames')" path="orgPositions">
            <NDynamicInput
              v-model:value="model.orgPositions"
              :min="1"
              :on-create="
                () => {
                  return { orgId: '', positionId: '' };
                }
              "
            >
              <template #default="{ value }">
                <NSpace class="w-596px">
                  <NTreeSelect
                    v-model:value="value.orgId"
                    :options="orgUnitTree"
                    key-field="id"
                    label-field="name"
                    default-expand-all
                    :max-tag-count="7"
                    :placeholder="$t('page.manage.user.form.userOrgUnit')"
                    class="w-290px"
                    :on-update:value="val => addPositionRecord(model.orgPositions.indexOf(value), val)"
                  />
                  <NSelect
                    v-model:value="value.positionId"
                    :options="positionRecord[value.orgId] || []"
                    :placeholder="$t('page.manage.user.form.userPosition')"
                    class="w-290px"
                  />
                </NSpace>
              </template>
              <template #action="{ index }">
                <NSpace class="w-100px">
                  <NButton size="medium" @click="addNewItem(index)">
                    <icon-ic:round-plus class="text-icon" />
                  </NButton>
                  <NButton size="medium" @click="removeItem(index)">
                    <icon-ic-round-remove class="text-icon" />
                  </NButton>
                </NSpace>
              </template>
            </NDynamicInput>
          </NFormItemGi>
        </template>
      </NGrid>
    </NForm>
    <template #footer>
      <NSpace justify="end">
        <NButton quaternary @click="closeModal">
          {{ $t('common.cancel') }}
        </NButton>
        <NButton type="primary" @click="handleSubmit">
          {{ $t('common.confirm') }}
        </NButton>
      </NSpace>
    </template>
  </NModal>
</template>
